package handle

import (
	"context"
	"fmt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"mxshop/mxshop_srvs/inventory_srv/global"
	"mxshop/mxshop_srvs/inventory_srv/model"
	"mxshop/mxshop_srvs/inventory_srv/proto"
	"time"

	goredislib "github.com/go-redis/redis/v8"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v8"
)

type InventoryServer struct {
	proto.UnimplementedInventoryServer
}

func (*InventoryServer) SetInv(ctx context.Context, req *proto.GoodsInvInfo) (*emptypb.Empty, error) {
	//设置库存
	var inv model.Inventory
	global.DB.Where(&model.Inventory{Goods: req.GoodsId}).First(&inv)
	inv.Goods = req.GoodsId

	inv.Stocks = req.Num
	global.DB.Save(&inv)
	return &emptypb.Empty{}, nil
}
func (*InventoryServer) InvDetail(ctx context.Context, req *proto.GoodsInvInfo) (*proto.GoodsInvInfo, error) {
	var inv model.Inventory
	global.DB.Where(&model.Inventory{Goods: req.GoodsId}).First(&inv)
	if res := global.DB.Where(&model.Inventory{Goods: req.GoodsId}).First(&inv); res.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "没有库存信息")
	}
	return &proto.GoodsInvInfo{
		GoodsId: inv.Goods,
		Num:     inv.Stocks,
	}, nil
}
func (*InventoryServer) Sell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {
	//事务
	//数据一致性
	//并发
	client := goredislib.NewClient(&goredislib.Options{
		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisInfo.Host, global.ServerConfig.RedisInfo.Port),
	})
	pool := goredis.NewPool(client)

	rs := redsync.New(pool)

	tx := global.DB.Begin()
	for _, goodInfo := range req.GoodsInfo {
		var inv model.Inventory

		mutexname := fmt.Sprintf("goods_%d", goodInfo.GoodsId)
		mutex := rs.NewMutex(mutexname)

		if err := mutex.Lock(); err != nil {
			return nil, status.Errorf(codes.Internal, "创建分布式锁错误")
		}
		if res := global.DB.Where(&model.Inventory{Goods: goodInfo.GoodsId}).First(&inv); res.RowsAffected == 0 {
			tx.Rollback()
			return nil, status.Errorf(codes.InvalidArgument, "参数错误")
		}
		if inv.Stocks < goodInfo.Num {
			tx.Rollback()
			return nil, status.Errorf(codes.ResourceExhausted, "库存不足")
		}

		//扣减，并发会出现数据不一致，通过锁
		inv.Stocks -= goodInfo.Num
		tx.Save(&inv)
		time.Sleep(7 * time.Second)
		if ok, err := mutex.Unlock(); !ok || err != nil {
			return nil, status.Errorf(codes.Internal, "释放分布式锁错误")
		}
	}
	tx.Commit() //提交
	return &emptypb.Empty{}, nil
}
func (*InventoryServer) Reback(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {
	//1.订单超时归还 2.订单创建失败 3.手动归还
	tx := global.DB.Begin()
	for _, goodInfo := range req.GoodsInfo {
		var inv model.Inventory
		if res := global.DB.Where(&model.Inventory{Goods: goodInfo.GoodsId}).First(&inv); res.RowsAffected == 0 {
			tx.Rollback()
			return nil, status.Errorf(codes.InvalidArgument, "参数错误")
		}

		//扣减，并发会出现数据不一致，通过锁
		inv.Stocks += goodInfo.Num
		tx.Save(&inv)
	}
	tx.Commit() //提交
	return &emptypb.Empty{}, nil
}
